package com.ljw.hmall.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljw.hmall.clients.ItemClient;
import com.ljw.hmall.dao.SearchMapper;


import com.ljw.hmall.dto.PageDTO;
import com.ljw.hmall.pojo.Item;
import com.ljw.hmall.pojo.ItemDoc;
import com.ljw.hmall.pojo.PageResult;
import com.ljw.hmall.pojo.Params;
import com.ljw.hmall.service.SearchService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl extends ServiceImpl<SearchMapper, Item> implements SearchService {
    @Autowired
    ItemClient itemClient;
    @Autowired
    RestHighLevelClient client;

    @Override
    public PageResult search(Params params) {

        try {
            //测试feign的拦截器
//            List<Item> items1 = itemClient.selectAll();
            // 1.准备Request
            SearchRequest request = new SearchRequest("item");
            // 2.准备请求参数
            // 2.1.query
            buildBasicQuery(params, request);
            // 2.2.分页
            int page = params.getPage();
            int size = params.getSize();
            request.source().from((page - 1) * size).size(size);
            //2.3.根据销量/价格排序
            String sortName = params.getSortBy();
            if (sortName!=null&&!"".equals(sortName)){
                if (sortName.equals("sold")){
                    request.source().sort(SortBuilders
                            .fieldSort("sold")
                            .order(SortOrder.ASC)
                    );
                }else if (sortName.equals("price")){
                    request.source().sort(SortBuilders
                            .fieldSort("price")
                            .order(SortOrder.ASC)
                    );
                }
            }
            // 3.发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);


            //如果索引库中没有文档数据，就批量插入文档数据
            SearchHit[] hits = response.getHits().getHits();
            if (hits==null&&hits.length<1){

                List<Item> items = itemClient.selectAll();
                //数据总数
                int count= items.size();
                //总页数
                int totalPage=count%size ==0 ? (count%size) : (count/size+1);
                for (int i = 1; i <=totalPage ; i++) {
                    PageDTO<Item> itemPageDTO = itemClient.selectByPage(page, size);
                    page=page+1;
                    List<Item> list = itemPageDTO.getList();
                    try {
                        BulkRequest bulkRequest = new BulkRequest();

                        for (Item item : list) {
                            ItemDoc itemDoc = new ItemDoc(item);

                            bulkRequest.add(new IndexRequest("item")
                                    .id(itemDoc.getId().toString())
                                    .source(JSON.toJSONString(itemDoc), XContentType.JSON)
                            );
                        }
                        //批量插入
                        client.bulk(bulkRequest, RequestOptions.DEFAULT);

                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }





            }
            // 4.解析响应
            return handleResponse(response);
        } catch (IOException e) {
            throw new RuntimeException("搜索数据失败", e);
        }

    }

    //=========================抽取的方法========================
    private void buildBasicQuery(Params params, SearchRequest request) {
        // 1.准备Boolean查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 1.1.关键字搜索，match查询，放到must中
        String key = params.getKey();
        if (StringUtils.isNotBlank(key)) {
            // 不为空，根据关键字查询
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        } else {
            // 为空，查询所有
            boolQuery.must(QueryBuilders.matchAllQuery());
        }

        // 1.2.品牌
        String brand = params.getBrand();
        if (StringUtils.isNotBlank(brand)) {
            boolQuery.filter(QueryBuilders.termQuery("brand", brand));
        }

        // 1.2.分类
        String category = params.getCategory();
        if (StringUtils.isNotBlank(category)) {
            boolQuery.filter(QueryBuilders.termQuery("category", category));
        }
        // 1.5.价格范围
        Integer minPrice = params.getMinPrice();
        Integer maxPrice = params.getMaxPrice();
        if (minPrice != null && maxPrice != null) {
            maxPrice = maxPrice == 0 ? Integer.MAX_VALUE : maxPrice;
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));
        }

        // 2.算分函数查询
        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
                boolQuery, // 原始查询，boolQuery
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ // function数组
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD", true), // 过滤条件
                                ScoreFunctionBuilders.weightFactorFunction(10) // 算分函数
                        )
                }
        );

        // 3.设置查询条件
        request.source().query(functionScoreQuery);
    }

    private PageResult handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        // 4.1.总条数
        long total = searchHits.getTotalHits().value;
        // 4.2.获取文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3.遍历
        List<ItemDoc> items = new ArrayList<>(hits.length);
        for (SearchHit hit : hits) {
            // 4.4.获取source
            String json = hit.getSourceAsString();
            // 4.5.反序列化，非高亮前的ItemDoc对象数据
            ItemDoc itemDoc = JSON.parseObject(json, ItemDoc.class);
            // 4.6.处理高亮结果
            // 1)获取高亮map
            Map<String, HighlightField> map = hit.getHighlightFields();
            if (map != null && !map.isEmpty()) {
                // 2）根据字段名，获取高亮结果
                HighlightField highlightField = map.get("name");
                if (highlightField != null) {
                    // 3）获取高亮结果字符串数组中的第1个元素
                    String hName = highlightField.getFragments()[0].toString();
                    // 4）把高亮结果放到ItemDoc中
                    itemDoc.setName(hName);

                }
            }

            // 4.9.放入集合
            items.add(itemDoc);
        }
        return new PageResult(total, items);
    }
}
